<?php

namespace App\Library\Payment\Wechat;

use App\Helpers\LogHelper;
use App\Library\Payment\BasePayment;
use WeChatPay\Builder;
use WeChatPay\BuilderChainable;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;

/**
 *
 */
class BaseWechatApi extends BasePayment
{
    protected static string $domain;
    protected static string $appId;
    protected static string $appSecret;
    protected static string $appPayId;
    protected static string $mchId;
    protected static string $serial;
    protected static string $mchSecretKey;
    protected static string $certPubKeyId;
    protected static string $certPem;
    protected static string $apiClientKeyPem;
    protected static string $apiClientCertPem;

    protected static string $notifyPath;

    // 支付相关接口地址
    const PAY_ORDER_APP         = 'v3/pay/transactions/app';                   // app下单获取支付信息
    const PAY_ORDER_CANCEL      = 'v3/pay/transactions/out-trade-no/%s/close'; // 关闭订单API
    const PAY_TRANSACTION_QUERY = 'v3/pay/transactions/out-trade-no/%s';       // 查询订单

    const PAY_ORDER_JSAPI = 'v3/pay/transactions/jsapi';   // 小程序下单获取支付信息

    // 用户相关接口地址
    const GET_ACCESS_TOKEN = '/sns/oauth2/access_token';   // 获取access_token
    const GET_USER_INFO    = '/sns/userinfo';              // 获取用户信息

    public function __construct()
    {
        $this->_init();
    }

    /**
     * @return void
     */
    private function _init()
    {
        self::$domain = config('wechat.domain');
        self::$appId = config('wechat.appId');
        self::$appSecret = config('wechat.appSecret');
        self::$appPayId = config('wechat.appId');
        self::$mchId = config('wechat.mchId');
        self::$serial = config('wechat.serial');
        self::$mchSecretKey = config('wechat.mchSecretKey');
        self::$certPubKeyId = config('wechat.certPubKeyId');
        self::$certPem = config('wechat.certPemPath');
        self::$apiClientKeyPem = config('wechat.apiClientKeyPemPath');
        self::$apiClientCertPem = config('wechat.apiClientCertPemPath');
        self::$notifyPath = config('wechat.notifyPath');
    }

    /**
     * @return BuilderChainable
     */
    protected function getInstance(): BuilderChainable
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = sprintf('file://%s', self::$apiClientKeyPem);
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

        // 从本地文件中加载「微信支付公钥」，用来验证微信支付应答的签名
        $platformPublicKeyFilePath = sprintf('file://%s', self::$certPem);
        $platformPublicKeyInstance = Rsa::from($platformPublicKeyFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 构造一个 APIv3 客户端实例
        return Builder::factory([
            'mchid' => self::$mchId,
            'serial' => self::$serial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                self::$certPubKeyId => $platformPublicKeyInstance,
            ],
        ]);
    }

    /**
     * @param $prepayId
     * @return array
     */
    protected function getAppPayParams($prepayId): array
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . self::$apiClientKeyPem;

        $params = [
            'appid' => self::$appId,
            'timestamp' => Formatter::timestamp(),
            'noncestr' => Formatter::nonce(),
            'prepayid' => $prepayId,
        ];

        $params['sign'] = Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $merchantPrivateKeyFilePath,
        );

        $params['partnerid'] = self::$mchId;
        $params['package'] = 'Sign=WXPay';

        LogHelper::info('payment', ['appPayParams' => $params]);
        return $params;
    }

    /**
     * @param $prepayId
     * @return array
     */
    protected function getAppletPayParams($prepayId): array
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . self::$apiClientKeyPem;

        $params = [
            'appid' => self::$appId,
            'timeStamp' => Formatter::timestamp(),
            'nonceStr' => Formatter::nonce(),
            'package' => sprintf("prepay_id=%s", $prepayId),
        ];

        $params['paySign'] = Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $merchantPrivateKeyFilePath,
        );
        $params['signType'] = 'RSA';
        $params['prepayid'] = $prepayId;
        LogHelper::info('payment', ['appPayParams' => $params]);

        return $params;
    }

    /**
     * 设置额外参数
     *
     * @return void
     */
    protected function setBatchOptional(&$requestData, $batchOptional)
    {
        if (!empty($batchOptional['timeExpire'])) {
            $requestData['time_expire'] = timestampToRFC($batchOptional['timeExpire']);
        }
        $attach = [];
        if (!empty($batchOptional['params'])) {
            $attach = $batchOptional['params'];
        }

        if (!empty($attach)) {
            $requestData['attach'] = json_encode($attach);
        }
    }

    /**
     * 获取域名
     *
     * @return string
     */
    protected function getDomain(): string
    {
        return self::$domain;
    }
}
